package uml.GUI;

import java.awt.Component;
import java.awt.Container;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.LinkedHashSet;
import javax.swing.JFileChooser;
import javax.swing.JLayeredPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import uml.FileIO.FileGenerator;
import uml.eventsystem.IObserver;
import uml.eventsystem.ISubject;
import uml.eventsystem.MouseHandler;
import uml.eventsystem.SubjectImpl;
import uml.eventsystem.events.UMLEvent;
import uml.eventsystem.events.UMLEventId;
import uml.layout.NoFlowLayout;
import uml.objects.AnchorPoint;
import uml.objects.ArrowManager;
import uml.objects.UMLObject;
import uml.util.UMLConstants;
import uml.util.UMLPrinter;
import uml.view.factory.UMLObjectFactory;

public class DiagramPanel
		extends JLayeredPane
		implements IObserver, ISubject, MouseListener
{
	private String name = this.getName ();
	final JFileChooser fc = new JFileChooser ();
	final FileNameExtensionFilter filter = new FileNameExtensionFilter ("A-Team Files", "ateam");
	private File file;
	private SubjectImpl m_subjectImplementation;
	private ArrowManager m_arrowManager;
	private String m_path;
	private LinkedHashSet<UMLObject> m_selectedObjects;

	/**
	 * Creates the default panel for holding the users diagram
	 */
	public DiagramPanel ()
	{
		super ();
		setBackground (UMLConstants.DIAGRAM_PANEL_BACKGROUND);
		setLayout (new NoFlowLayout ());
		m_selectedObjects = new LinkedHashSet<UMLObject> ();
		this.addMouseListener (MouseHandler.getMouseHandler ());
		m_subjectImplementation = new SubjectImpl (this);
		m_arrowManager = new ArrowManager (this);
		this.add (m_arrowManager, new Integer (0));
	}

	public void add (UMLObject umlObject)
	{
		if (umlObject == null)
			return;
		if (umlObject instanceof AnchorPoint)
			m_arrowManager.add ((AnchorPoint) umlObject);
		else
		{
			this.add (umlObject.getComponent (), umlObject.getLayer ());
			umlObject.registerObserver (this);
			umlObject.getComponent ().setVisible (true);
		}
		validate ();
	}

	private void multiSelect (Object object)
	{
		if (object instanceof UMLObject)
		{
			UMLObject umlObject = (UMLObject) object;
			moveToFront (umlObject.getComponent ());
			if (!m_selectedObjects.add ((UMLObject) object))
			{
				//if the object is already in the list unselect it.
				m_selectedObjects.remove (object);
				umlObject.unselect ();
			}
			else
				umlObject.select ();
		}
	}

	private void deleteObjects ()
	{
		for (UMLObject umlObject : m_selectedObjects)
		{
			if (umlObject instanceof AnchorPoint)
			{
				m_arrowManager.delete ((AnchorPoint) umlObject);
			}
			else
			{
				remove (umlObject.getComponent ());
				umlObject.notifyObservers (UMLEventId.DELETE);
			}
		}
		clearSelectedObjects ();
	}

	private void clearSelectedObjects ()
	{
		for (UMLObject umlObject : m_selectedObjects)
			umlObject.unselect ();
		m_selectedObjects.clear ();
	}

	private void createObject (UMLEventId eventId)
	{
		UMLObject umlObject = UMLObjectFactory.createUMLObject (eventId);
		if (umlObject != null)
			add (umlObject);
	}

	private void print ()
	{
		UMLPrinter.printComponent (this);
	}

	private void save ()
	{
		if (m_path == null)
		{
			fc.setFileFilter (filter);
			int returnVal = fc.showSaveDialog (this);
			if (returnVal == JFileChooser.CANCEL_OPTION)
			{
				return;
			}
			else
			{
				saveAs (fc.getSelectedFile ().getName ());

			}
		}
		else
		{
			FileGenerator.saveDiagram (m_path, this);

		}

	}

	private void saveAs (String fileName)
	{
		file = fc.getSelectedFile ();
		name = file.getName ();
		String [] temp = name.split ("\\.");
		name = temp[0];
		String [] path = file.getPath ().split ("\\.");
		FileGenerator.saveDiagram (path[0], this);
		this.setName (name);
		

		UMLTabbedPane parent = (UMLTabbedPane) this.getParent ();
		int index = parent.getSelectedIndex ();
		parent.remove (this);
		parent.addTab (this.getName(), this);
		parent.setSelectedIndex (index);
		this.setPath (fileName);
		
	}

	public void setPath (String path)
	{
		String[] temp = path.split ("\\.");
		m_path = temp[0];
	}

	@Override
	public void handleNotification (UMLEvent event)
	{
		switch (event.getEventId ())
		{
		case SELECT:
			if(m_selectedObjects.contains(event.getSource()))
				break;
			clearSelectedObjects ();
			if (event.getSource () instanceof UMLObject)
			{
				UMLObject source = (UMLObject) event.getSource ();
				m_selectedObjects.add (source);
				moveToFront (source.getComponent ());
				source.select ();
			}
			break;
		case MULTI_SELECT:
			multiSelect (event.getSource ());
			break;
		case CANCEL_MENU:
			if (event.getSource () instanceof UMLContextMenu)
			{
				UMLContextMenu source = (UMLContextMenu) event.getSource ();
				source.setVisible (false);
			}
			repaint();
			break;
			
		case DELETE:
			if (event.getSource () instanceof UMLContextMenu)
			{
				UMLContextMenu source = (UMLContextMenu) event.getSource ();
				source.setVisible (false);
			}
			deleteObjects ();
			repaint ();
			break;
		case TRANSLATE:
			for (UMLObject umlObject : m_selectedObjects)
				umlObject.translate (MouseHandler.m_dp);
			break;
		case PRINT:
			print ();
			break;
		case SAVE:
			save ();
			break;
		case SAVEAS:
			fc.setFileFilter (filter);
			int returnVal = fc.showSaveDialog (this);
			if (returnVal == JFileChooser.CANCEL_OPTION)
			{
				return;
			}
			else
			{
				saveAs (fc.getSelectedFile ().getName ());
			}
			break;
		case ANCHOR:
			if (event.getSource () instanceof AnchorPoint)
			{
				AnchorPoint p = (AnchorPoint) event.getSource ();
				Component c = this.findComponentAt (p.getPoint ());
				while (!(c instanceof UMLObject) && c != null)
					c = c.getParent();
				if(c instanceof UMLObject && !(c instanceof AnchorPoint))
					p.setContext ((Container) c);
				else
					p.setContext(this);
			}
			break;
		case REPAINT:
			this.repaint();
			break;
		default:
			if (event.getEventId ().is (UMLEventId.FACTORY))
				createObject (event.getEventId ());
			break;
		}
	}

	@Override
	public void addObserver (IObserver observer, UMLEventId eventId)
	{
		m_subjectImplementation.addObserver (observer, eventId);
	}

	@Override
	public void removeObserver (IObserver observer, UMLEventId eventId)
	{
		m_subjectImplementation.removeObserver (observer, eventId);
	}

	@Override
	public void notifyObservers (UMLEventId eventId)
	{
		m_subjectImplementation.notifyObservers (eventId);
	}

	@Override
	public void mouseClicked(MouseEvent arg0) 
	{
		
	}

	@Override
	public void mouseEntered(MouseEvent arg0) 
	{
		
	}

	@Override
	public void mouseExited(MouseEvent arg0) 
	{
		
	}

	@Override
	public void mousePressed(MouseEvent event) 
	{
		for(UMLObject umlObject : m_selectedObjects)
			umlObject.unselect();
		m_selectedObjects.clear();
		MouseHandler.getMouseHandler().setContextMenuVisible(false);
	}

	@Override
	public void mouseReleased(MouseEvent arg0) 
	{
		
	}
}